package org.myspring;

import org.myspring.annotation.Autowired;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author shanzhenbo
 * @date 2023/6/8 15:43
 * @return
 */
public class MyAnnotationConfigApplicationContext implements BeanDefinitionRegistry {

    /**
     * beadDefinition读取器
     */
    private final BeanDefinitionReader reader;

    /**
     * 单例池
     */
    Map<String, Object> singletonObjects = new HashMap<>();

    /**
     * beanDefinitionMap
     */
    Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    /**
     * beanPostProcessorList
     */
    List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

    public MyAnnotationConfigApplicationContext(Class<?>... classes) {
        this();
        this.register(classes);
        // 创建单例bean
        createSingleton();

    }

    @Override
    public void register(Class<?>[] classes) {
        this.reader.scan(classes);
    }


    public MyAnnotationConfigApplicationContext() {
        this.reader = new BeanDefinitionReader(this);
    }


    public Object getBean(String beanName) {
        if (beanDefinitionMap.containsKey(beanName)) {
            BeanDefinition myBeanDefinition = beanDefinitionMap.get(beanName);
            if ("singleton".equals(myBeanDefinition.getScope())) {
                // 判断singletonObjects是否存在beanName
                if (singletonObjects.containsKey(beanName)) {
                    return singletonObjects.get(beanName);
                }
                // 不存在则创建bean
                else {
                    Object bean = createBean(myBeanDefinition);
                    this.addSingleton(beanName, bean);
                    return bean;
                }
            } else {
                return createBean(myBeanDefinition);
            }
        } else {
            throw new RuntimeException("不存在name为" + beanName + "的bean");
        }
    }

    private void createSingleton() {
        //遍历beanDefinitionMap
        beanDefinitionMap.forEach((beanName, beanDefinition) -> {
            // 判断singletonObjects是否存在beanName
            if (!singletonObjects.containsKey(beanName)) {
                // 判断scope是否为singleton
                if ("singleton".equals(beanDefinition.getScope())) {
                    // 创建bean
                    Object bean = createBean(beanDefinition);
                    // 存入singletonObjects
                    this.addSingleton(beanName, bean);
                }
            }
        });
    }

    private Object createBean(BeanDefinition beanDefinition) {
        Class beanClass = beanDefinition.getBeanClass();
        try {
            // 创建bean，这个步骤就是bean的实例化
            Object instance = beanClass.newInstance();

            // 执行beanPostProcessor的前置方法
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessAfterInitialization(instance, beanDefinition.getBeanName());
            }

            // 依赖注入
            for (Field declaredField : beanClass.getDeclaredFields()) {
                if (declaredField.isAnnotationPresent(Autowired.class)) {
                    // 获取属性的类型
                    Class<?> type = declaredField.getType();
                    // 设置属性的值
                    declaredField.setAccessible(true);
                    declaredField.set(instance, getBean(declaredField.getName()));
                }
            }

            // 初始化后
            if (instance instanceof InitializingBean) {
                ((InitializingBean) instance).afterPropertiesSet();
            }

            // 执行beanPostProcessor的后置方法
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanDefinition.getBeanName());
            }

            return instance;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void addSingleton(String beanName, Object bean) {
        singletonObjects.put(beanName, bean);
    }

    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        beanPostProcessorList.add(beanPostProcessor);
    }

    @Override
    public void addBeadDefinition(String beanName, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(beanName, beanDefinition);
    }


}
